/***************************************************************************
 *cr
 *cr            (C) Copyright 1995-2019 The Board of Trustees of the
 *cr                        University of Illinois
 *cr                         All Rights Reserved
 *cr
 ***************************************************************************/

/***************************************************************************
 * RCS INFORMATION:
 *
 *      $RCSfile: ToolFltkMenu.C,v $
 *      $Author: johns $        $Locker:  $             $State: Exp $
 *      $Revision: 1.35 $       $Date: 2019/01/17 21:21:02 $
 *
 ***************************************************************************
 * DESCRIPTION:
 *  generated by Fast Light User Interface Designer (fluid) version 1.0100
 ***************************************************************************/

#include "ToolFltkMenu.h"
#include "P_CmdTool.h"
#include "VMDApp.h"
#include "P_UIVR.h"
#include "P_Tool.h"
#include "FL/forms.H"  // for legacy color definitions

static void createtool_cb(Fl_Widget *, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->create_tool();
}
static void deletetool_cb(Fl_Widget *, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->delete_tool();
}
static void select_tool_cb(Fl_Widget *w, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->select_tool();
}
static void select_tool_type_cb(Fl_Widget *, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->select_tool_type();
}
static void position_cb(Fl_Widget *w, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  Fl_Choice *menu = (Fl_Choice *)w;
  if (menu->value() == 0)
    self->choose_tracker(NULL);
  else
    self->choose_tracker(menu->text());
}
static void force_cb(Fl_Widget *w, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  Fl_Choice *menu = (Fl_Choice *)w;
  if (menu->value() == 0)
    self->choose_feedback(NULL);
  else
    self->choose_feedback(menu->text());
}
static void button_cb(Fl_Widget *w, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  Fl_Choice *menu = (Fl_Choice *)w;
  if (menu->value() == 0)
    self->choose_buttons(NULL);
  else
    self->choose_buttons(menu->text());
}
static void offset_cb(Fl_Widget *, void *v) { 
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->set_offset();
}
static void positionscale_cb(Fl_Widget *, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->set_positionscale();
} 
static void forceconstant_cb(Fl_Widget *, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->set_springscale();
}
static void forcescale_cb(Fl_Widget *, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->set_forcescale();
}
static void toolrep_cb(Fl_Widget *, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->set_toolrep();
}
static void moleculerep_cb(Fl_Widget *, void *v) {
  ToolFltkMenu *self = (ToolFltkMenu *)v;
  self->update_replist();
  self->set_toolrep();
}
   
void ToolFltkMenu::make_window() {
  size(540, 335);
  { 
    { Fl_Box* o = new Fl_Box(15, 15, 325, 160);
      o->box(FL_ENGRAVED_FRAME);
    }
    { Fl_Button* o = new Fl_Button(25, 30, 125, 25, "Create tool");
      o->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
#if defined(VMDMENU_WINDOW)
      o->color(VMDMENU_WINDOW, FL_GRAY);
#endif
      o->callback(createtool_cb, this);
    }
    { Fl_Choice* o = tooltypechooser = new Fl_Choice(25, 80, 125, 25, "Set tool type:");
      o->down_box(FL_BORDER_BOX);
      o->align(FL_ALIGN_TOP_LEFT);
      o->color(VMDMENU_CHOOSER_BG, VMDMENU_CHOOSER_SEL);
      o->callback(select_tool_type_cb, this);
    }
    {
      Fl_Button *o = new Fl_Button(25, 120, 125, 25, "Delete tool");
#if defined(VMDMENU_WINDOW)
      o->color(VMDMENU_WINDOW, FL_GRAY);
#endif
      o->callback(deletetool_cb, this);
    }
    toolbrowser = new Fl_Hold_Browser(175, 30, 155, 135);
    toolbrowser->color(VMDMENU_BROWSER_BG, VMDMENU_BROWSER_SEL);
    toolbrowser->callback(select_tool_cb, this);
    { Fl_Box* o = new Fl_Box(350, 15, 175, 160, "label");
      o->box(FL_ENGRAVED_FRAME);
      o->labeltype(FL_NO_LABEL);
    }
    { Fl_Box* o = new Fl_Box(20, 5, 45, 25, "Tools");
      o->box(FL_FLAT_BOX);
#if defined(VMDMENU_WINDOW)
      o->color(VMDMENU_WINDOW, FL_GRAY);
#endif
    }
    { Fl_Box* o = new Fl_Box(355, 5, 100, 25, "Tool devices");
      o->box(FL_FLAT_BOX);
#if defined(VMDMENU_WINDOW)
      o->color(VMDMENU_WINDOW, FL_GRAY);
#endif
    }
    { Fl_Choice* o = positionchooser = new Fl_Choice(360, 50, 150, 25, "Position");
      o->down_box(FL_BORDER_BOX);
      o->align(FL_ALIGN_TOP_LEFT);
      o->color(VMDMENU_CHOOSER_BG, VMDMENU_CHOOSER_SEL);
      o->callback(position_cb, this);
    }
    { Fl_Choice* o = buttonchooser = new Fl_Choice(360, 95, 150, 25, "Buttons");
      o->down_box(FL_BORDER_BOX);
      o->align(FL_ALIGN_TOP_LEFT);
      o->color(VMDMENU_CHOOSER_BG, VMDMENU_CHOOSER_SEL);
      o->callback(button_cb, this);
    }
    { Fl_Choice* o = forcechooser = new Fl_Choice(360, 140, 150, 25, "Force Feedback");
      o->down_box(FL_BORDER_BOX);
      o->align(FL_ALIGN_TOP_LEFT);
      o->color(VMDMENU_CHOOSER_BG, VMDMENU_CHOOSER_SEL);
      o->callback(force_cb, this);
    }
    { Fl_Tabs* o = tooltabs = new Fl_Tabs(15, 185, 510, 150);
#if defined(VMDMENU_WINDOW)
      o->color(VMDMENU_WINDOW, FL_GRAY);
      o->selection_color(VMDMENU_WINDOW);
#endif

      { Fl_Group* o = new Fl_Group(40, 210, 485, 125, "Position");
#if defined(VMDMENU_WINDOW)
        o->color(VMDMENU_WINDOW, FL_GRAY);
        o->selection_color(VMDMENU_WINDOW);
#endif
        xoffsetinput = new Fl_Value_Input(105, 230, 65, 25, "X Offset:");
        xoffsetinput->selection_color(VMDMENU_VALUE_SEL);
        xoffsetinput->step(.01);
        xoffsetinput->range(-100, 100);
        xoffsetinput->callback(offset_cb, this);
        yoffsetinput = new Fl_Value_Input(105, 260, 65, 25, "Y Offset:");
        yoffsetinput->selection_color(VMDMENU_VALUE_SEL);
        yoffsetinput->step(.01);
        yoffsetinput->range(-100, 100);
        yoffsetinput->callback(offset_cb, this);
        zoffsetinput = new Fl_Value_Input(105, 290, 65, 25, "Z Offset:");
        zoffsetinput->selection_color(VMDMENU_VALUE_SEL);
        zoffsetinput->step(.01);
        zoffsetinput->range(-100, 100);
        zoffsetinput->callback(offset_cb, this);
        positionscalinginput = new Fl_Value_Input(295, 230, 65, 25, "Position scaling:");
        positionscalinginput->selection_color(VMDMENU_VALUE_SEL);
        positionscalinginput->step(0.01);
        positionscalinginput->range(0.01, 100);
        positionscalinginput->callback(positionscale_cb, this);
        o->end();
      }
      { Fl_Group* o = new Fl_Group(40, 210, 485, 125, "Force");
#if defined(VMDMENU_WINDOW)
        o->color(VMDMENU_WINDOW, FL_GRAY);
        o->selection_color(VMDMENU_WINDOW);
#endif
        o->hide();
        forceconstantinput = new Fl_Value_Input(180, 230, 60, 25, "Feedback scaling:");
        forceconstantinput->selection_color(VMDMENU_VALUE_SEL);
        forceconstantinput->step(0.1);
        forceconstantinput->range(0.1, 100);
        forceconstantinput->callback(forceconstant_cb, this);
        forcescalinginput = new Fl_Value_Input(180, 260, 60, 25, "Applied force scaling:");
        forcescalinginput->selection_color(VMDMENU_VALUE_SEL);
        forcescalinginput->step(0.1);
        forcescalinginput->range(0.1, 100);
        forcescalinginput->callback(forcescale_cb, this);
        o->end();
      }
      { Fl_Group* o = new Fl_Group(40, 210, 485, 125, "Assigned Rep");
#if defined(VMDMENU_WINDOW)
        o->color(VMDMENU_WINDOW, FL_GRAY);
        o->selection_color(VMDMENU_WINDOW);
#endif
        o->hide();
        { Fl_Round_Button* o = forceatombutton = new Fl_Round_Button(45, 245, 200, 25, "Apply force to picked atom");
          o->down_box(FL_ROUND_DOWN_BOX);
          o->type(FL_RADIO_BUTTON);
          o->callback(toolrep_cb, this);
        }
        { Fl_Round_Button* o = forcerepbutton = new Fl_Round_Button(45, 270, 200, 25, "Apply force to molecule rep");
          o->down_box(FL_ROUND_DOWN_BOX);
          o->type(FL_RADIO_BUTTON);
          o->callback(toolrep_cb, this);
        }
        { Fl_Choice* o = repmoleculechooser = new Fl_Choice(280, 245, 205, 25, "Selected molecule:");
          o->down_box(FL_BORDER_BOX);
          o->align(FL_ALIGN_TOP_LEFT);
          o->color(VMDMENU_CHOOSER_BG, VMDMENU_CHOOSER_SEL);
          o->callback(moleculerep_cb, this);
        }
        { Fl_Choice* o = reprepchooser = new Fl_Choice(280, 290, 205, 25, "Selected rep:");
          o->down_box(FL_BORDER_BOX);
          o->align(FL_ALIGN_TOP_LEFT);
          o->color(VMDMENU_CHOOSER_BG, VMDMENU_CHOOSER_SEL);
          o->callback(toolrep_cb, this);
        }
        o->end();
      }
      o->end();
    }
  }
}

void ToolFltkMenu::reset_device_menus() {
  ResizeArray<JString *> *trackers, *feedback, *buttons;
  positionchooser->clear();
  buttonchooser->clear();
  forcechooser->clear();
  
  positionchooser->add("None");
  buttonchooser->add("None");
  forcechooser->add("None");

  trackers = app->uivr->get_tracker_names();
  feedback = app->uivr->get_feedback_names();
  buttons = app->uivr->get_button_names();

  int t;
  for (t=0; t<trackers->num(); t++) {
    positionchooser->add(*(*trackers)[t]); // XXX valgrind FMR
    delete (*trackers)[t];
  }
  for (t=0; t<feedback->num(); t++) {
    forcechooser->add(*(*feedback)[t]); // XXX valgrind FMR
    delete (*feedback)[t];
  }
  for (t=0; t<buttons->num(); t++) {
    buttonchooser->add(*(*buttons)[t]); // XXX valgrind FMR
    delete (*buttons)[t];
  }
  delete trackers;
  delete feedback;
  delete buttons;
}

void ToolFltkMenu::reset_tool_list() {
  int curline = toolbrowser->value();
  toolbrowser->clear();
  for (int t=0; t<app->uivr->num_tools(); t++) {
    if (app->uivr->gettool(t)->alive()) {
      toolbrowser->add(app->uivr->gettool(t)->type_name());
    }
  }
  toolbrowser->value(curline);
}
void ToolFltkMenu::create_tool() {
  const char *tooltype = tooltypechooser->text();
  app->tool_create(tooltype, 0, NULL);
}

void ToolFltkMenu::delete_tool() {
  app->tool_delete(toolbrowser->value()-1);
}

void ToolFltkMenu::select_tool_type() {
  int n = toolbrowser->value();
  const char *type = tooltypechooser->text(tooltypechooser->value());
  app->tool_change_type(n-1, type);
}

void ToolFltkMenu::select_tool() {
  int n = toolbrowser->value();
  if (n == 0 && toolbrowser->size() == 1) {
    // choose the one and only item.
    n = 1;
    toolbrowser->value(1);
  } 
  Tool *tool = app->uivr->gettool(n-1);
  if (!tool || !tool->alive()) {
    positionchooser->deactivate();
    buttonchooser->deactivate();
    forcechooser->deactivate();
    tooltabs->deactivate();
  } else {
    for (int k=0; k<tooltypechooser->size()-1; k++) {
      if (!strcmp(tooltypechooser->text(k), tool->type_name())) {
        tooltypechooser->value(k);
        break;
      }
    }
    positionchooser->activate();
    positionchooser->value(0);
    buttonchooser->activate();
    buttonchooser->value(0);
    forcechooser->activate();
    forcechooser->value(0);
    tooltabs->activate();
    const char *pos = tool->get_tracker();
    const char *but = tool->get_buttons();
    const char *fce = tool->get_feedback();
    if (pos) {
      // start counting at 1 because the first entry is "None"
      for (int t=1; t<positionchooser->size()-1; t++) {
        if (!strcmp(positionchooser->text(t), pos))
          positionchooser->value(t);
      }
    }
    if (but) {
      for (int t=1; t<buttonchooser->size()-1; t++) {
        if (!strcmp(buttonchooser->text(t), but))
          buttonchooser->value(t);
      }
    }
    if (fce) {
      for (int t=1; t<forcechooser->size()-1; t++) {
        if (!strcmp(forcechooser->text(t), fce))
          forcechooser->value(t);
      }
    }
    const float *offset = tool->getoffset();
    if (offset) {
      xoffsetinput->value(offset[0]);
      yoffsetinput->value(offset[1]);
      zoffsetinput->value(offset[2]);
    } else {
      xoffsetinput->value(0);
      yoffsetinput->value(0);
      zoffsetinput->value(0);
    }
    forcescalinginput->value(tool->getforcescale());
    forceconstantinput->value(tool->getspringscale());
    positionscalinginput->value(tool->getscale());

    update_toolrep_choosers();
  }
}

void ToolFltkMenu::choose_tracker(const char *dev) {
  app->uivr->set_tracker(toolbrowser->value()-1, dev);
  select_tool();
}
void ToolFltkMenu::choose_feedback(const char *dev) {
  app->uivr->set_feedback(toolbrowser->value()-1, dev);
  select_tool();
}
void ToolFltkMenu::choose_buttons(const char *dev) {
  app->uivr->set_buttons(toolbrowser->value()-1, dev);
  select_tool();
}

void ToolFltkMenu::set_offset() {
  int n = toolbrowser->value();
  if (n > 0) {
    float offset[3];
    offset[0] = (float)xoffsetinput->value();
    offset[1] = (float)yoffsetinput->value();
    offset[2] = (float)zoffsetinput->value();
    runcommand(new CmdToolOffset(offset, n-1));
  }
}
void ToolFltkMenu::set_forcescale() {
  int n = toolbrowser->value();
  if (n > 0) {
    float newval = (float)forcescalinginput->value();
    if (newval < 0) newval = -1.0f/newval;
    app->tool_set_force_scale(n-1, newval);
  }
}
void ToolFltkMenu::set_springscale() {
  int n = toolbrowser->value();
  if (n > 0) {
    float newval = (float)forceconstantinput->value();
    if (newval < 0) newval = -1.0f/newval;
    app->tool_set_spring_scale(n-1, newval);
  }
}
void ToolFltkMenu::set_positionscale() {
  int n = toolbrowser->value();
  if (n > 0) {
    float newval = (float)positionscalinginput->value();
    if (newval < 0) newval = -1.0f/newval;
    app->tool_set_position_scale(n-1, newval);
  }
}

void ToolFltkMenu::set_toolrep() {
  int n = toolbrowser->value();
  if (n > 0) {
    if (forcerepbutton->value()) {
      int molid = app->molecule_id(repmoleculechooser->value()-1);
      int repid = reprepchooser->value()-1;
      runcommand(new CmdToolRep(n-1, molid, repid));
    } else {
      runcommand(new CmdToolRep(n-1, -1, -1));
    }
  }
}

void ToolFltkMenu::update_toolrep_choosers() {
  // Blow away the current settings only if the tool has a 
  // valid selected tool rep.  
   
  int has_valid_rep = FALSE;
  int molid = -1;
  int repid = -1;
  int molind = 0, repind;
  int n = toolbrowser->value();
  const Tool *tool = app->uivr->gettool(n-1);
  if (tool) {
    molid = tool->get_rep_molid();
    const char *rep = tool->get_rep_name();
    repid = app->molrep_get_by_name(molid, rep);
    if (repid >= 0) has_valid_rep = TRUE;
  }
  if (has_valid_rep) {
    for (int m=0; m<app->num_molecules(); m++)
      if (molid == app->molecule_id(m)) 
        molind = m+1;
    repind = repid+1;
  } else {
    molind = repmoleculechooser->value();
    repind = reprepchooser->value();
  }
  
  fill_fltk_molchooser(repmoleculechooser, app, "None");
  if (molind >= 0 && molind < repmoleculechooser->size()-1) {
    repmoleculechooser->value(molind);
  } else {
    repmoleculechooser->value(0);
  }

  reprepchooser->clear();
  update_replist();
  if (repind >= reprepchooser->size()-1)
    repind = 0;
  reprepchooser->value(repind);

  if (has_valid_rep) {
    forcerepbutton->setonly();
  } else {
    forceatombutton->setonly();
  }
}
  
void ToolFltkMenu::update_replist() {
  int molid = app->molecule_id(repmoleculechooser->value()-1);
  reprepchooser->clear();
  reprepchooser->add("None");
  reprepchooser->value(0);
  for (int r=0; r<app->num_molreps(molid); r++) {
    const char *sel = app->molrep_get_selection(molid, r);
    char *buf = new char[strlen(sel)+10];
    sprintf(buf, "%d: %s", r, sel);
    reprepchooser->add(buf);
    delete [] buf;
  }
}
   

  
// commands we are interested in
static int cmdList[6] = {
  Command::TOOL_CREATE, Command::TOOL_DELETE, Command::TOOL_CHANGE,
  Command::TOOL_OFFSET, Command::TOOL_ADD_DEVICE, Command::TOOL_DELETE_DEVICE
};

static int toolrepCmdList[6] = {
  Command::MOL_NEW,     Command::MOL_DEL,
  Command::MOL_RENAME,
  Command::MOL_MODREP,  Command::MOL_DELREP,
  Command::TOOL_REP
};
  
ToolFltkMenu::ToolFltkMenu(VMDApp *vmdapp)
: VMDFltkMenu("tool", "Tool Controls", vmdapp) {
  int t;

  make_window();
  for (t=0; t<app->uivr->num_tool_types(); t++) 
    tooltypechooser->add(app->uivr->tool_name(t));
  tooltypechooser->value(0);
  reset_device_menus();

  for (t=0; t < 6; command_wanted(cmdList[t++]));
  for (t=0; t < 6; command_wanted(toolrepCmdList[t++]));
  command_wanted(Command::TOOL_SCALE);
  command_wanted(Command::TOOL_SCALE_FORCE);
  command_wanted(Command::TOOL_SCALE_SPRING);
  positionchooser->value(0);
  buttonchooser->value(0);
  forcechooser->value(0);

  forceatombutton->setonly();
}

int ToolFltkMenu::act_on_command(int type, Command *) {
  int t;
  for (t=0; t<6; t++) if (type == cmdList[t]) {
    reset_tool_list();
    select_tool();
    return TRUE;
  }
  for (t=0; t<6; t++) if (type == toolrepCmdList[t]) {
    update_toolrep_choosers(); 
    return TRUE;
  }
  if (type == Command::TOOL_SCALE ||
      type == Command::TOOL_SCALE_FORCE ||
      type == Command::TOOL_SCALE_SPRING) {
    select_tool();
    return TRUE;
  }
  return FALSE;
}

